/*!
    \copyright  Copyright (c) 2024 Qualcomm Technologies International, Ltd.
                All Rights Reserved.
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \file
    @{
        \ingroup    adkfs
        \brief      Describes the interface that needs to be provided by adkfs providers

*/
#ifndef ADKFS_PROVIDER_IF_H
#define ADKFS_PROVIDER_IF_H

#include "adkfs_types.h"

#include <message.h>

#include <stdint.h>

#define ADKFS_PATH_SEPARATOR            "/"     /*< Path separator character */
#define ADKFS_PATH_SEPARATOR_LEN        (sizeof(ADKFS_PATH_SEPARATOR) - 1)

#define ADKFS_MAX_PROVIDERS             (4)
#define ADKFS_MAX_LEN_PROVIDER_ROOT     (4)

typedef enum {
    ADKFS_PROVIDER_INIT_MSGS_PROVIDER_INIT_COMPLETE = 1,
    ADKFS_PROVIDER_INIT_MSGS_CHECK_ALL_PROVIDERS_COMPLETE,
} adkfs_provider_init_msgs_t;

typedef struct adkfs_provider_if_t {
    /*! The root path string will be used to match the right provider from the path provided.
     *  The root path should start with ADKFS_PATH_SEPARATOR and omit any trailing ADKFS_PATH_SEPARATOR
     * Valid Examples:
     *      /ra
     *      /ro
     *      /mem
     * 
     * Invalid example:
     *      /ra/
    */
    const char      root_path[ADKFS_MAX_LEN_PROVIDER_ROOT];
    /* Optional, only needed if the provider needs to perform init tasks at registration time.
     * \return TRUE if initialization is complete after the call to Init
     *         FALSE if initialization is asynchronous, in which case AdkFs will wait for a MESSAGE_ADKFS_PROVIDER_INIT_COMPLETE message from the provider
     *         Overall AdkFs initialization won't complete until all providers have finished initialization
    */
    bool            (*Init)(Task provider_init_task);
    int32_t         (*Fopen)(void **handle, const char *path, adkfs_access_flags_t access);
    int32_t         (*Fsize)(void* handle, size_t *fsize);
    int32_t         (*Fmap)(void* handle, const void **fbuffer);
    int32_t         (*Funmap)(void* handle);
    /*! To reduce code duplication in offset calculations providers only need to implement
     *  a seek function to get the offset from the beginning of the file. The relative
     *  positions for the different "whence" anchors is calculated by adkfs with the help
     *  of the Ftell and Fsize functions.
     */
    int32_t         (*Fseek)(void* handle, size_t offset);
    int32_t         (*Ftell)(void* handle, size_t *offset);
    int32_t         (*Fread)(void* handle, void *buf_ptr, size_t read_size, size_t *bytes_read);
    int32_t         (*Fwrite)(void* handle, const void *buf_ptr, size_t write_size, size_t *bytes_written);
    int32_t         (*Fclose)(void* handle);
    int32_t         (*Fdelete)(const char *path);
} adkfs_provider_if_t;

void AdkFs_RegisterProvider(const adkfs_provider_if_t* interface);

const adkfs_provider_if_t* AdkFs_GetProvider(const char *path);

#endif /* ADKFS_PROVIDER_IF_H */